package com.example.base_model.heart

import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.Job
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.cancel
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch

/**
 * @Author jiangKunKun
 * @CreateDate 2025/10/1
 * @Description 一个可重用的心跳控制器，用于管理和监控一个周期性信号的健康状况。
 * 它可以用于多种场景，例如：
 * - **WebSocket Keep-Alive**: 监控是否在规定时间内收到了服务器的 ping/pong 消息。
 * - **网络连接检查**: 定期检查网络是否可用。
 * - **用户活动跟踪**: 监控用户是否在一段时间内有活动。
 * 它通过协程和 Flow 实现，提供了发送心跳、监控超时和状态管理的功能。
 * @SpittingGrooves
 */
class HeartbeatController {
    /**
     * 专用于此控制器实例的协程作用域。
     * - **GlobalScope.coroutineContext**: 继承全局作用域的上下文，使其生命周期独立于任何特定的 UI 组件。
     * - **SupervisorJob**: 关键所在。使用 SupervisorJob 意味着如果此作用域内的一个子协程失败，
     *   它不会取消整个作用域或其他的子协程。这对于心跳监控至关重要，
     *   因为我们不希望监听和超时检测这两个独立的任务互相影响。
     */
    private val sendScope = CoroutineScope(GlobalScope.coroutineContext + SupervisorJob())

    /**
     * 心跳“事件”流。
     * - 使用 [MutableSharedFlow] 是因为它是一个“热”流，可以向所有当前的订阅者广播事件。
     * - 当 `sendHeartbeat` 被调用时，它会向这个流发射一个值。
     */
    private val heartEventFlow = MutableSharedFlow<Boolean>()

    /**
     * 内部可变的心跳“状态”。
     * - 它代表了心跳的当前最新状态（`true` 表示活跃，`false` 表示不活跃）。
     * - 这是 `StateFlow`，意味着它总是有值的，并且只发射最新的值。
     */
    private val _currentState = MutableStateFlow(false)

    /**
     * 对外暴露的只读心跳“状态”流。
     * - UI 或其他服务可以安全地从此 [StateFlow] 中收集状态，以响应心跳的活跃/不活跃变化。
     */
    val currentState: StateFlow<Boolean> = _currentState

    /**
     * 持有心跳监控任务的协程 Job，用于在需要时停止监控。
     */
    private var monitoringJob: Job? = null

    /**
     * 最后一次接收到“活跃”心跳信号的时间戳（毫秒）。
     */
    private var lastHeartbeatTime = System.currentTimeMillis()

    /**
     * 当前心跳值的副本，主要用于超时检测时的状态判断。
     * - 使用 [@Volatile] 是因为此变量可能被多个协程（运行在不同线程上）同时访问和修改：
     *   一个协程（`heartEventFlow.collect`）写入它，另一个协程（超时检测 `while` 循环）读取它。
     * - `@Volatile` 保证了对这个变量的写入会立即对其他线程可见，防止数据不一致。
     */
    @Volatile
    private var currentHeartbeatValue = false

    /**
     * 获取心跳事件流，允许外部订阅原始的心跳事件。
     * @return [Flow] 心跳事件流。
     */
    fun getEventFlow(): Flow<Boolean> = heartEventFlow

    /**
     * 获取当前心跳状态的快照值。
     * @return [Boolean] 当前心跳状态，`true` 表示活跃，`false` 表示不活跃。
     */
    fun getCurrentState(): Boolean = _currentState.value

    /**
     * 获取最后一次活跃心跳的时间戳。
     * @return [Long] 最后一次接收到“活跃”心跳信号的时间戳（毫秒）。
     */
    fun getLastHeartbeatTime(): Long = lastHeartbeatTime

    /**
     * 发送一个心跳信号。这是外部触发心跳的入口点。
     * @param heart 心跳信号值，`true` 表示心跳正常（活跃），`false` 表示心跳停止（不活跃）。
     */
    fun sendHeartbeat(heart: Boolean) {
        // 在专用的协程作用域中启动一个“即发即忘”的任务来处理心跳信号。
        sendScope.launch {
            // 1. 将心跳事件发射到 SharedFlow，通知所有事件监听者。
            heartEventFlow.emit(heart)
            // 2. 更新 StateFlow，让状态订阅者知道最新的状态。
            _currentState.value = heart
        }
    }

    /**
     * 开始监听心跳并检测超时。
     * 如果已经有一个监控任务在运行，它将不会重复启动。
     *
     * @param timeoutMillis 超时时间（毫秒）。如果超过这个时间未收到活跃心跳，则触发超时逻辑。
     * @param callback 超时回调函数。当心跳超时时执行。
     */
    fun startMonitoring(
        timeoutMillis: Long,
        callback: () -> Unit
    ) {
        // 如果监控任务已在运行，则直接返回，避免重复启动。
        if (monitoringJob?.isActive == true) return

        // 启动一个新的监控任务，并将其赋值给 monitoringJob 属性。
        monitoringJob = sendScope.launch {
            // 1. 启动一个子协程来专门监听心跳事件流。
            launch {
                heartEventFlow.collect { value ->
                    // a. 更新当前心跳值的副本。
                    currentHeartbeatValue = value
                    // b. 如果是“活跃”心跳，则更新最后一次心跳时间。
                    if (value) {
                        lastHeartbeatTime = System.currentTimeMillis()
                    }
                }
            }

            // 2. 启动另一个独立的子协程来循环检测超时。
            launch {
                // 只要父 Job (monitoringJob) 处于活跃状态，就持续循环。
                while (isActive) {
                    // a. 每秒检查一次超时状态。
                    delay(1000)
                    // b. 计算自上次活跃心跳以来的时间差。
                    val timeSinceLastHeartbeat = System.currentTimeMillis() - lastHeartbeatTime
                    // c. 如果时间差超过了设定的超时阈值...
                    if (timeSinceLastHeartbeat > timeoutMillis) {
                        // d. ...并且当前状态仍然是“活跃”，则触发超时逻辑。
                        //    这个检查 (`currentHeartbeatValue`) 至关重要，它防止了在心跳已经变为`false`后，
                        //    超时回调被重复触发。
                        if (currentHeartbeatValue) {
                            // i. 发送一个“不活跃”心跳信号，以统一更新所有状态和事件监听者。
                            sendHeartbeat(false)
                            // ii. 执行外部传入的超时回调函数。
                            callback()
                        }
                    }
                }
            }
        }
    }

    /**
     * 停止心跳监控。
     * 这会取消正在运行的监控任务并重置所有状态。
     */
    fun stopMonitoring() {
        // 取消父监控 Job，这将同时取消其内部的所有子协程（监听和超时检测）。
        monitoringJob?.cancel()
        monitoringJob = null
        // 重置内部状态为初始值。
        currentHeartbeatValue = false
        _currentState.value = false
    }

    /**
     * 彻底销毁控制器，清理所有资源。
     * 这应该在控制器完全不再需要时调用，例如在 ViewModel 被清除或应用退出时。
     */
    fun destroy() {
        // 1. 确保所有监控任务都已停止。
        stopMonitoring()
        // 2. 取消整个 sendScope。一旦作用域被取消，就不能再用它启动任何新的协程。
        sendScope.cancel()
    }
}
